package com.speedcar.base.util;

import com.alibaba.fastjson.JSONObject;
import com.speedcar.base.exception.ErrorCode;
import com.speedcar.base.exception.SpeedCarCommonException;
import com.speedcar.base.model.ThirdTranData;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

@Slf4j
public class AesUtil {

    private static final String AES_ALGORITHM = "AES";
    private static final String AES_ALGORITHM_ECB = "AES/ECB/PKCS5Padding";

    /**
     * 生成128位AES密钥
     */
    public static SecretKey generateAESKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM);
            keyGenerator.init(128); // 128位密钥
            return keyGenerator.generateKey();
        } catch (NoSuchAlgorithmException e) {
            log.error("生成密钥失败", e);
            throw new SpeedCarCommonException(ErrorCode.OTHER_ERROR, "生成密钥失败");
        }
    }

    /**
     * 加载AES密钥
     * 该方法接受一个Base64编码的密钥字符串，将其解码并生成一个AES密钥对象
     *
     * @param secret Base64编码的密钥字符串
     * @return SecretKey AES密钥对象，用于加密和解密数据
     */
    public static SecretKey loadAESKey(String secret) {
        // 根据Base64编码的密钥字符串生成AES密钥对象
        return new SecretKeySpec(Base64.getDecoder().decode(secret), AES_ALGORITHM);
    }


    /**
     * 使用AES加密字符串
     *
     * @param data   待加密的字符串
     * @param secret 用于加密的密钥
     * @return 加密后的字节数组
     */
    public static String encrypt(String secret, String data) {
        try {
            // 获取AES算法的Cipher实例
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            // 初始化Cipher为加密模式，并传入密钥
            cipher.init(Cipher.ENCRYPT_MODE, loadAESKey(secret));
            // 使用Cipher对字符串进行加密，并返回加密后的字节数组
            byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            log.error("加密失败", e);
            throw new SpeedCarCommonException(ErrorCode.OTHER_ERROR, "数据加密失败");
        }
    }


    /**
     * 使用AES解密
     */
    public static String decrypt(String secret, ThirdTranData<?> thirdTranData) {
//        if (secondBetween(System.currentTimeMillis(), thirdTranData.getTimestamp()) > 3) {
//            log.error("验签失败，请求已过期，tranData：{} ", JSONObject.toJSONString(thirdTranData));
//            throw new SpeedCarCheckException(ErrorCode.SIGN_EXPIRED);
//        }
        // 解密
        try {
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM_ECB);
            cipher.init(Cipher.DECRYPT_MODE, loadAESKey(secret));
            byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(thirdTranData.getSignData()));
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            log.error("解密失败", e);
            throw new SpeedCarCommonException(ErrorCode.SIGN_ERROR);
        }

    }


    /**
     * 示例：演示AES加解密流程
     */
    public static void main(String[] args) {
        Long now = System.currentTimeMillis();

        ThirdTranData thirdTranData = new ThirdTranData();
        thirdTranData.setAppKey("chaboshi");

        String carInfoJson = "{\n" +
                "  \"dealerId\": 903,\n" +
                "  \"carId\": 9610\n" +
                "}";

        thirdTranData.setTimestamp(now);

        // 生成或加载密钥
        String secret = "rM7nQpKQvlwJpFQnFlBc8Q==";

        // 加密
        String encryptedBase64 = encrypt(secret, carInfoJson);
        thirdTranData.setSignData(encryptedBase64);
        System.out.println("Original: " + JSONObject.toJSONString(thirdTranData));

        decrypt(secret, thirdTranData);

    }

    /**
     * 获取两个时间之间相差的秒数绝对值
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return 相差的时间（秒）
     */
    private static long secondBetween(Long startDate, Long endDate) {
        return Math.abs(startDate - endDate) / 1000;
    }
}
